<?php

$up = new Upload(['maxSize' => 2000000]);
echo $up->upload('fy');

class Upload
{
	// 上传文件路径
	protected $path = './upload/';
	// 允许上传文件后缀
	protected $allowSuffix = ['jpg', 'jpeg', 'png', 'gif'];
	// 允许上传的mime
	protected $allowMime = ['image/jpeg', 'image/png', 'image/gif'];
	// 允许上传文件的size
	protected $maxSize = 200000;
	// 是否启用随机名
	protected $isRandName = true;
	// 新文件的前缀
	protected $prefix = 'up_';

	// 错误码
	protected $errorNumber = 0;
	// 错误信息
	protected $errorInfo = "";

	// 旧文件名
	protected $oldName;
	// 新文件名
	protected $newName;
	// 文件大小
	protected $size;
	// 文件后缀
	protected $suffix;
	// 文件mime
	protected $mime;
	// 文件临时路径
	protected $tmpName;


	public function __construct($param = [])
	{
		foreach ($param as $key => $value) {
			$this->setOptions($key, $value);
		}
	}

	// 初始化参数
	protected function setOptions($key, $value)
	{
		// 获取当前成员属性
		$keys = array_keys(get_class_vars(__CLASS__));
		// 判断当前参数是否在成员属性内
		if(in_array($key, $keys)){
			$this->$key = $value;
		}
	}

	// 文件上传函数 $key是input框中的name属性值
	public function upload($key)
	{
		// 判断有没有设置路径
		if($this->path == ""){
			$this->errorNumber = -1;
			return false;
		}
		// 判断该路径是否存在，是否可写
		if(!$this->check()){
			$this->errorNumber = -2;
			return false;
		}
		// 判断$_FILES里面的error信息是否为0，如果为0，则说明文件信息可以在服务器端获取。提取文件信息保存到成员属性
		$error = $_FILES[$key]['error'];
		if($error){
			$this->errorNumber = $error;
			return false;
		}else{
			// 提取文件的相关信息,并保存到成员属性中
			$this->getFileInfo($key);
		}

		// 判断文件大小，mime，后缀是否符合
		if(!$this->checkSize() || !$this->checkMime() || !$this->checkSuffix()){
			return false;
		}
		// 得到新的名字
		$this->getNewName();


		
		// 判断是否是上传文件，并且移动到上传文件夹
		if(is_uploaded_file($this->tmpName)){
			if(move_uploaded_file($this->tmpName, $this->path.$this->newName)){
				return $this->path.$this->newName;
			}else{
				$this->errorNumber = -7;
				return false;
			}
		}else{
			$this->errorNumber = -6;
			return false;
		}
	}

	protected function check()
	{
		// 文件夹不存在或不是目录，创建文件夹
		if(!file_exists($this->path) || !is_dir($this->path)){
			return mkdir($this->path, 0777, true);
		}

		// 判断文件夹是否可写
		if(!is_writable($this->path)){
			return chmod($this->path, 0777);
		}

		return true;
	}

	protected function getFileInfo($key)
	{
		// 得到文件名字
		$this->oldName = $_FILES[$key]['name'];
		// 得到文件的mime类型
		$this->mime = $_FILES[$key]['type'];
		// 得到文件的临时路径
		$this->tmpName = $_FILES[$key]['tmp_name'];
		// 得到文件大小
		$this->size = $_FILES[$key]['size'];
		// 得到文件后缀
		$this->suffix = pathinfo($this->oldName)['extension'];

	}

	protected function checkSize()
	{
		if($this->size > $this->maxSize){
			$this->errorNumber = -3;
			return false;
		}
		return true;
	}

	protected function checkSuffix()
	{
		if(!in_array($this->suffix, $this->allowSuffix)){
			$this->errorNumber = -4;
			return false;
		}
		return true;
	}

	protected function checkMime()
	{
		if(!in_array($this->mime, $this->allowMime)){
			$this->errorNumber = -5;
			return false;
		}
		return true;
	}

	// 获取新文件名
	protected function getNewName()
	{
		if($this->isRandName === true){
			$this->newName = $this->prefix.uniqid().".".$this->suffix;
		}else{
			$this->newName = $this->oldName;
		}
	}

	public function __get($name)
	{
		if($name === 'errorNumber'){
			return $this->errorNumber;
		}else if($name === 'errorInfo'){
			return $this->getErrorInfo();
		}
	}

	protected function getErrorInfo()
	{
		$str = '';
		switch ($this->errorNumber) {
			case -1:
				$str = '文件路径没有设置';
				break;
			case -2:
				$str = '文件路径不是目录或者没有权限';
				break;
			case -3:
				$str = '文件大小超过指定范围';
				break;
			case -4:
				$str = '文件后缀名不符合';
				break;
			case -5:
				$str = '文件mime类型不符合';
				break;
			case -6:
				$str = '不是上传文件';
				break;
			case -7:
				$str = '文件上传失败';
				break;
			case 1:
				$str = '文件超出php.ini设置大小';
				break;
			case 2:
				$str = '文件超出HTML设置大小';
				break;
			case 3:
				$str = '文件部分上传';
				break;
			case 4:
				$str = '没有文件上传';
				break;
			case 6:
				$str = '找不到错误文件';
				break;
			case 7:
				$str = '文件写入失败';
				break;
			default:
				$str = 'success';
				break;
		}

		return $str;
	}
}